﻿using System;
using System.Configuration;
using System.Reflection;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using EasySL.Server.Interface;

namespace EasySL.Server
{
    public class ServerApp
    {
        public ServerApp()
        { 
        }

        private void WriteLine(string s, bool withTime)
        {
            Console.WriteLine((withTime ? "[" + DateTime.Now.ToString() + "]\r\n" : string.Empty) + s);
        }

        public void Run()
        {
            Console.Title = "EasySL Server";

            if (!this.DoStart())
                Environment.Exit(1);

            bool running = true;
            while (running)
            {
                try
                {
                    running = InterpretCommand();
                }
                catch (Exception e)
                {
                    Logger.LogException(e.InnerException);
                }
            }
            this.DoStop();
            Environment.Exit(0);
        }

        private bool InterpretCommand()
        {
            Logger.LogTextLine("EasySL Server>");
            string commands = Console.ReadLine();
            switch (commands.ToLower())
            {
                case "exit":
                    return false;
                default:
                    break;
            }
            return true;
        }

        private bool DoStart()
        {
            Logger.LogInformation("EasySL Server starting");

            this.implServer = this.StartServer();
            if (this.implServer != null)
            {
                this.implServer.Initialize();
            }

            Logger.LogTextLine("EasySL Server started successfully");

            return this.implServer != null;
        }

        private bool DoStop()
        {
            Logger.LogTextLine("EasySL Server stopping --------");

            if (this.implServer != null)
            {
                this.implServer.UnInitialize();
            }

            this.StopServer();
            Logger.LogTextLine("EasySL Server stopped Successfully --------");
            return true;
        }

        private IServer StartServer()
        {
            try
            {
                ChannelServices.RegisterChannel(new TcpChannel(ServerPort), false);
            }
            catch
            {
                Logger.LogTextLine(string.Format("Can not start server at port: {0}", ServerPort));
                return null;
            }

            RemotingConfiguration.ApplicationName = ServerName;
            try
            {
                RemotingConfiguration.RegisterWellKnownServiceType(typeof(ServerImpl),
                    ServerName + ".rem", WellKnownObjectMode.Singleton);
            }
            catch
            {
                Logger.LogTextLine(string.Format("Can not register service: {0}", ServerName));
                return null;
            }
            Logger.LogTextLine(string.Format("Service successfully started at port: {0}", ServerPort));

            IServer server = null;
            try
            {
                string serviceUrl = "tcp://localhost:" + ServerPort + "/" + ServerName + ".rem";
                server = (IServer)Activator.GetObject(typeof(IServer), serviceUrl);
            }
            catch (Exception)
            {
                Logger.LogTextLine(string.Format("Cannot connect to the server: {0}", ServerPort));
                server = null;
            }
            return server;
        }

        private void StopServer()
        {
            try
            {
                ChannelServices.UnregisterChannel(new TcpChannel(ServerPort));
            }
            catch
            {
                Logger.LogTextLine(string.Format("Can not stop server at port: {0}", ServerPort));
            }
        }

        private static readonly string ServerName = ConfigurationManager.AppSettings["ServerName"];
        private static readonly int ServerPort = int.Parse(ConfigurationManager.AppSettings["ServerPort"]);
        private IServer implServer = null;
    }
}
